package mspbots.hubspot.common;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * mspbots.data.autotask.utils.QueryBody
 * <a href="https://www.autotask.net/help/DeveloperHelp/Content/AdminSetup/2ExtensionsIntegrations/APIs/REST/API_Calls/REST_Basic_Query_Calls.htm">Making basic query calls to the Autotask PSA REST API</a>
 * <br>
 * Grouping query
 * JSON syntax
 * To use this query, replace each of the following placeholders with the values described.
 * <p>
 * GroupingOperator fields: Designate the type of search you'd like to perform by entering an operator value. When working with grouping operators, you may select AND or OR.
 * FilterExpression fields: Enter the filter expressions you'd like to send for your query, as described in the earlier sections of this article. You may include operator values from the list of filter operators.
 * <code>
 * {
 * "filter": [
 * {
 * "op": "eq",
 * "field": "IsActive",
 * "value": true
 * },
 * {
 * "op": "or",
 * "items": [
 * {
 * "op": "eq",
 * "field": "lastname",
 * "value": "Smith"
 * },
 * {
 * "op": "eq",
 * "field": "lastname",
 * "value": "Jones"
 * },
 * {
 * "op": "and",
 * "items": [
 * {
 * "op": "eq",
 * "field": "firstname",
 * "value": "Chris"
 * },
 * {
 * "op": "eq",
 * "field": "lastname",
 * "value": "Brady"
 * }
 * ]
 * }
 * ]
 * }
 * ]
 * }
 * </code>
 *
 * @author <a href="https://github.com/vnobo">Alex bob</a>
 * @date Created by 2020/7/9
 */
@Data
@NoArgsConstructor
@ApiModel("Hubspot api query model")
public class QueryBody {

    @ApiModelProperty(value = "Specifying the maximum records to return. default 100", example = "100")
    private int limit;

    @ApiModelProperty(value = "To access the next page of results, you must pass the parameter provided in " +
            "the property of the previous response. If the property isn’t provided, there are no additional results to display." +
            " Note: The parameter is expected to be a string.afterpaging.next.afterpaging.next.afterafter", example = "100")
    private int after;

    @NotNull(message = "Properties cannot be null, You can specify the default []")
    @ApiModelProperty(value = "Specifying fields to return. example:id,name")
    private Set<String> properties;

    @Valid
    @ApiModelProperty(value = "Filter operators, default: {\n \"filter\": [\n{\n\"operator\": " +
            "\"GTE\",\n\"propertyName\": \"id\",\n \"value\": \"0\"\n}\n]\n}")
    private List<Map<String, List<FilterExpression>>> filterGroups;

    @Valid
    @NotNull(message = "Find filters expression cannot be null")
    @ApiModelProperty(value = "Filter operators, default: {\n \"filter\": [\n{\n\"operator\": " +
            "\"GTE\",\n\"propertyName\": \"id\",\n \"value\": \"0\"\n}\n]\n}")
    private List<FilterExpression> filters;

    @ApiModelProperty(value = "Use a sorting rule in the request body to see results in a specific order (ascending or descending)." +
            " Only one sorting rule can be applied to any search.")
    private List<Object> sorts;

    @Builder
    public QueryBody(int limit, Set<String> properties, List<FilterExpression> filters,
                     List<Map<String, List<FilterExpression>>> filterGroups,
                     int after, List<Object> sorts) {
        this.limit = limit;
        this.properties = properties;
        this.filters = filters;
        this.filterGroups = filterGroups;
        this.after = after;
        this.sorts = sorts;
    }

    /**
     * default query params
     * max records 25, id>0
     *
     * @return default query body
     */
    public static QueryBody withDefault() {
        return new QueryBody(100, Set.of(), List.of(FilterExpression.withDefault()), List.of(), 0, List.of());
    }

    /**
     * query params with FilterExpression
     * max records 500
     *
     * @param filter fiter expression
     * @return default query body
     */
    public static QueryBody withFilter(FilterExpression filter) {
        QueryBody queryBody = withDefault();
        queryBody.setFilters(List.of(filter));
        return queryBody;
    }

    /**
     * query params with FilterExpression
     * max records 500
     *
     * @param filters fiter expression
     * @return default query body
     */
    public static QueryBody withFilters(List<FilterExpression> filters) {
        QueryBody queryBody = withDefault();
        queryBody.setFilters(filters);
        return queryBody;
    }
}
